﻿using System;
using System.Collections.Generic;
using System.Text;
using AIStudio.Wpf.DiagramDesigner;
using Newtonsoft.Json;
using System.Linq;
using System.Windows.Media;
using AIStudio.Wpf.Flowchart.ViewModels;

namespace AIStudio.Wpf.Flowchart.Models
{
    public static class DiagramDataExtention
    {       
        #region ToJson
        public static string ToJson(this IDiagramViewModel diagram)
        {
            var json = JsonConvert.SerializeObject(new {
                Nodes = diagram.Items.OfType<DesignerItemViewModelBase>().Select(p => p.ToDiagramNode()).Where(p => p != null),
                Links = diagram.Items.OfType<ConnectorViewModel>().Select(p => p.ToDiagramLink()).Where(p => p != null)
            }, new JsonSerializerSettings
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore
            });

            return json;
        }

        public static DiagramNode ToDiagramNode(this DesignerItemViewModelBase nodeModel)
        {
            DiagramNode diagramNode;
            if (nodeModel is FlowNode flowNode)
            {
                var flowchartNode = new FlowchartNode();
                diagramNode = flowchartNode;

                diagramNode.Name = flowNode.Name;
                flowchartNode.Color = flowNode.Color;
                flowchartNode.Kind = flowNode.Kind;
                if (nodeModel is MiddleFlowNode middleflowNode)
                {
                    flowchartNode.UserIds = middleflowNode.UserIds;
                    flowchartNode.RoleIds = middleflowNode.RoleIds;
                    flowchartNode.ActType = middleflowNode.ActType;
                }
            }
            else
            {
                return null;
            }

            diagramNode.Id = nodeModel.Id.ToString();
            if (nodeModel.ParentId != new Guid())
            {
                diagramNode.ParentId = nodeModel.ParentId.ToString();
            }
            diagramNode.Label = nodeModel.Text;
            diagramNode.Width = nodeModel.ItemWidth * nodeModel.Parent.ScreenScale;
            diagramNode.Height = nodeModel.ItemHeight * nodeModel.Parent.ScreenScale;
            diagramNode.X = nodeModel.Left * nodeModel.Parent.ScreenScale;
            diagramNode.Y = nodeModel.Top * nodeModel.Parent.ScreenScale;
            diagramNode.ZIndex = nodeModel.ZIndex;
            diagramNode.Type = diagramNode.GetType().Name;
            diagramNode.PortAlignmentList = nodeModel.Connectors.Select(p => p.Orientation.ToString()).ToList();

            return diagramNode;
        }

        public static DiagramLink ToDiagramLink(this ConnectorViewModel linkModel)
        {
            DiagramLink diagramLink = new DiagramLink();

            diagramLink.Id = linkModel.Id.ToString();
            diagramLink.Color = SerializeHelper.SerializeColor(linkModel.ColorViewModel.LineColor.Color);
            diagramLink.SelectedColor = SerializeHelper.SerializeColor(Colors.Black);
            diagramLink.Width = linkModel.ColorViewModel.LineWidth;
            diagramLink.Label = linkModel.Text;

            if (linkModel.SinkConnectorInfo is FullyCreatedConnectorInfo sinkConnector)
            {
                diagramLink.SourceId = linkModel.SourceConnectorInfo.DataItem.Id.ToString();
                diagramLink.TargetId = sinkConnector.DataItem.Id.ToString();

                //线条形状与箭头待处理
                //diagramLink.Router = baseLinkModel.Router?.Method.Name;
                //diagramLink.PathGenerator = baseLinkModel.PathGenerator?.Method.Name;
                //diagramLink.SourceMarkerPath = baseLinkModel.SourceMarker?.Path;
                //diagramLink.SourceMarkerWidth = baseLinkModel.SourceMarker?.Width;
                //diagramLink.TargetMarkerPath = baseLinkModel.TargetMarker?.Path;
                //diagramLink.TargetMarkerWidth = baseLinkModel.TargetMarker?.Width;

                diagramLink.Type = diagramLink.GetType().Name;

                diagramLink.SourcePortAlignment = linkModel.SourceConnectorInfo.Orientation.ToString();
                diagramLink.TargetPortAlignment = sinkConnector.Orientation.ToString();
            }
            else
            {
                return null;
            }
            return diagramLink;
        }
        #endregion

        #region ToObject
        public static void ToObject(this IDiagramViewModel diagram, string json)
        {
            var data = JsonConvert.DeserializeObject<DiagramData>(json, new JsonConverter[] { new DiagramNodeConverter(), new DiagramLinkConverter() });
            if (data != null)
            {
                ToObject(diagram, data);
            }
        }
        public static void ToObject(this IDiagramViewModel diagram, DiagramData data)
        {
            diagram.Items.Clear();

            List<DesignerItemViewModelBase> nodes = new List<DesignerItemViewModelBase>();
            if (data.Nodes != null)
            {
                foreach (var node in data.Nodes)
                {
                    var nodemodel = node.ToNodelModel(diagram);
                    nodes.Add(nodemodel);
                    diagram.Items.Add(nodemodel);
                }
            }
            if (data.Links != null)
            {
                foreach (var link in data.Links)
                {
                    var source = nodes.FirstOrDefault(p => p.Id == new Guid(link.SourceId));
                    var target = nodes.FirstOrDefault(p => p.Id == new Guid(link.TargetId));
                    var linkmodel = link.ToLinkModel(diagram, source, target);
                    diagram.Items.Add(linkmodel);
                }
            }
        }

        private static DesignerItemViewModelBase ToNodelModel(this DiagramNode diagramNode, IDiagramViewModel diagram)
        {
            DesignerItemViewModelBase nodeModel;
            if (diagramNode is FlowchartNode flowchartNode)
            {
                FlowNode flowNode = null;
                switch (flowchartNode.Kind)
                {
                    case NodeKinds.Start:
                        {
                            var flowchartNodelModel = new StartFlowNode();
                            flowNode = flowchartNodelModel;
                            break;
                        }

                    case NodeKinds.End:
                        {
                            var flowchartNodelModel = new EndFlowNode();
                            flowNode = flowchartNodelModel;
                            break;
                        }
                    case NodeKinds.Decide:
                        {
                            var flowchartNodelModel = new DecideFlowNode();
                            flowNode = flowchartNodelModel;
                            break;
                        }
                    case NodeKinds.COBegin:
                        {
                            var flowchartNodelModel = new COBeginFlowNode();
                            flowNode = flowchartNodelModel;
                            break;
                        }
                    case NodeKinds.COEnd:
                        {
                            var flowchartNodelModel = new COEndFlowNode();
                            flowNode = flowchartNodelModel;
                            break;
                        }
                    case NodeKinds.Middle:
                        {
                            var flowchartNodelModel = new MiddleFlowNode();
                            flowNode = flowchartNodelModel;
                            flowchartNodelModel.UserIds = flowchartNode.UserIds?.ToList();
                            flowchartNodelModel.RoleIds = flowchartNode.RoleIds?.ToList();
                            flowchartNodelModel.ActType = flowchartNode.ActType;
                            break;
                        }
                    default:
                        {
                            var flowNodelModel = new FlowNode(NodeKinds.Normal);
                            flowNode = flowNodelModel;
                            break;
                        }

                }

                nodeModel = flowNode;
                flowNode.Name = flowchartNode.Name;
                flowNode.Color = flowchartNode.Color;
                flowNode.Kind = flowchartNode.Kind;

            }
            else
            {
                nodeModel = new TextDesignerItemViewModel();
            }

            nodeModel.Id = new Guid(diagramNode.Id);
            if (!string.IsNullOrEmpty(diagramNode.ParentId))
            {
                nodeModel.ParentId = new Guid(diagramNode.ParentId);
            }
            nodeModel.Parent = diagram;
            nodeModel.Text = diagramNode.Label;
            nodeModel.ItemWidth = diagramNode.Width / diagram.ScreenScale;
            nodeModel.ItemHeight = diagramNode.Height / diagram.ScreenScale;
            nodeModel.Left = diagramNode.X / diagram.ScreenScale;
            nodeModel.Top = diagramNode.Y / diagram.ScreenScale;
            nodeModel.ZIndex = diagramNode.ZIndex;
            diagramNode.PortAlignmentList?.ForEach(p => nodeModel.AddConnector(new FullyCreatedConnectorInfo(nodeModel, p.ToEnum<ConnectorOrientation>())));

            return nodeModel;
        }

        public static ConnectorViewModel ToLinkModel(this DiagramLink diagramLink, IDiagramViewModel diagram, DesignerItemViewModelBase sourceNode, DesignerItemViewModelBase targetNode)
        {
            FullyCreatedConnectorInfo sourceConnectorInfo = sourceNode.Connectors.FirstOrDefault(p => p.Orientation.ToString() == diagramLink.SourcePortAlignment);
            FullyCreatedConnectorInfo sinkConnectorInfo = targetNode.Connectors.FirstOrDefault(p => p.Orientation.ToString() == diagramLink.TargetPortAlignment);
            ConnectorViewModel linkModel = new ConnectorViewModel(diagram, sourceConnectorInfo, sinkConnectorInfo, diagram.DrawModeViewModel?.VectorLineDrawMode ?? DrawMode.BoundaryConnectingLine);
            linkModel.Id = new Guid(diagramLink.Id);
            linkModel.ColorViewModel.LineColor.Color = SerializeHelper.DeserializeColor(diagramLink.Color);
            linkModel.ColorViewModel.LineWidth = diagramLink.Width;
            if (!string.IsNullOrEmpty(diagramLink.Label))
            {
                linkModel.AddText(diagramLink.Label);
            }
            //线条形状与箭头待处理
            //switch (diagramLink.Router)
            //{
            //    case "Normal": linkModel.Router = Routers.Normal; break;
            //    case "Orthogonal": linkModel.Router = Routers.Orthogonal; break;
            //}
            //switch (diagramLink.PathGenerator)
            //{
            //    case "Smooth": linkModel.PathGenerator = PathGenerators.Smooth; break;
            //    case "Straight": linkModel.PathGenerator = PathGenerators.Straight; break;

            //}

            //if (!string.IsNullOrEmpty(diagramLink.SourceMarkerPath))
            //{
            //    linkModel.SourceMarker = new LinkMarker(diagramLink.SourceMarkerPath, diagramLink.SourceMarkerWidth ?? 10.0);
            //}
            //if (!string.IsNullOrEmpty(diagramLink.TargetMarkerPath))
            //{
            //    linkModel.TargetMarker = new LinkMarker(diagramLink.TargetMarkerPath, diagramLink.TargetMarkerWidth ?? 10.0);
            //}
            return linkModel;
        }
        #endregion
    }
}
